Free Information Xchange presents: Sin v1.05 - CD crack by Static Vengeance - May 21st, 1999 REQUIREMENTS: Full game install W32Dasm & Hex editor Sin is another first person shooter like Quake and so many others. In fact Sin uses the Quake II engine for it's 3D engine. Like Quake II (early versions), Sin has a CD check and it's also very much like the Quake II CD check. So let's get right to work on this one. First disassemble sin.exe and go to the menu bar and select refs and then select "String data references" from the drop down menu. From the refs box that comes up, grab the slider bar and scroll down looking for anything interesting. Part way down you'll come across "\sin.exe" which is a ref to the game file. Many times this can be part of the CD check. So double click this ref and let's see what it gets us. Doing so puts you in the middle of this routine: * Referenced by a CALL at Address: |:00465DE6 <-- Called only once | :00465620 83EC50 sub esp, 00000050 :00465623 8D442404 lea eax, dword ptr [esp+04] :00465627 53 push ebx <-- Store original ebx value :00465628 33DB xor ebx, ebx <-- Zero out ebx for pass/fail flag :0046562A 50 push eax :0046562B 6819000200 push 00020019 :00465630 53 push ebx * Possible StringData Ref from Data Obj ->"Software\Ritual Entertainment\Sin" <-- Registry key | :00465631 6894DB4800 push 0048DB94 :00465636 6802000080 push 80000002 :0046563B 881DD8045100 mov byte ptr [005104D8], bl <-- Store lowest 8 bits of ebx in flag * Reference To: ADVAPI32.RegOpenKeyExA, Ord:012Eh | :00465641 FF1508C04700 Call dword ptr [0047C008] :00465647 85C0 test eax, eax :00465649 0F85F1000000 jne 00465740 <-- Have an error? Jump to exit :0046564F 8B442408 mov eax, dword ptr [esp+08] :00465653 8D4C240C lea ecx, dword ptr [esp+0C] :00465657 56 push esi :00465658 51 push ecx :00465659 8D542418 lea edx, dword ptr [esp+18] :0046565D 68D8045100 push 005104D8 :00465662 52 push edx :00465663 53 push ebx * Possible StringData Ref from Data Obj ->"PATH" <-- Get the path of the CD | :00465664 688CDB4800 push 0048DB8C :00465669 50 push eax :0046566A C744242880000000 mov [esp+28], 00000080 * Reference To: ADVAPI32.RegQueryValueExA, Ord:0136h <-- Get it from the registry | :00465672 FF1504C04700 Call dword ptr [0047C004] :00465678 8B4C240C mov ecx, dword ptr [esp+0C] :0046567C 8BF0 mov esi, eax :0046567E 51 push ecx * Reference To: ADVAPI32.RegCloseKey, Ord:0117h | :0046567F FF1500C04700 Call dword ptr [0047C000] :00465685 3BF3 cmp esi, ebx :00465687 5E pop esi :00465688 0F85B2000000 jne 00465740 :0046568E 6A01 push 00000001 * Reference To: KERNEL32.SetErrorMode, Ord:0213h | :00465690 FF15C4C04700 Call dword ptr [0047C0C4] * Possible StringData Ref from Data Obj ->"\sin.exe" <-- The file to be checked for | :00465696 6880DB4800 push 0048DB80 :0046569B 68D8045100 push 005104D8 :004656A0 8D54241C lea edx, dword ptr [esp+1C] * Possible StringData Ref from Data Obj ->"%s%s" | :004656A4 6810694800 push 00486910 :004656A9 52 push edx :004656AA E8E1820000 call 0046D990 :004656AF 8D442424 lea eax, dword ptr [esp+24] * Possible StringData Ref from Data Obj ->"r" <-- Read the file | :004656B3 687CDB4800 push 0048DB7C :004656B8 50 push eax :004656B9 E8B2770000 call 0046CE70 :004656BE 83C418 add esp, 00000018 :004656C1 3BC3 cmp eax, ebx :004656C3 7475 je 0046573A :004656C5 8A0DD8045100 mov cl, byte ptr [005104D8] :004656CB 50 push eax :004656CC 884C2408 mov byte ptr [esp+08], cl :004656D0 C64424093A mov [esp+09], 3A :004656D5 C644240A5C mov [esp+0A], 5C :004656DA 885C240B mov byte ptr [esp+0B], bl :004656DE E8DD760000 call 0046CDC0 :004656E3 83C404 add esp, 00000004 :004656E6 8D542404 lea edx, dword ptr [esp+04] <-- Load the current drive to check :004656EA 52 push edx <-- Push current drive to check * Reference To: KERNEL32.GetDriveTypeA, Ord:00DFh <-- Commonly used in CD check routines | :004656EB FF15C0C04700 Call dword ptr [0047C0C0] :004656F1 83F805 cmp eax, 00000005 <-- 05 is the value for a CD rom drive :004656F4 7544 jne 0046573A <-- Exit out if not a CD Rom drive :004656F6 57 push edi :004656F7 BFD8045100 mov edi, 005104D8 :004656FC 83C9FF or ecx, FFFFFFFF :004656FF 33C0 xor eax, eax :00465701 33D2 xor edx, edx :00465703 F2 repnz :00465704 AE scasb :00465705 F7D1 not ecx :00465707 49 dec ecx :00465708 7425 je 0046572F :0046570A B32F mov bl, 2F * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:0046572D(C) | :0046570C 80BAD80451005C cmp byte ptr [edx+005104D8], 5C :00465713 7506 jne 0046571B :00465715 889AD8045100 mov byte ptr [edx+005104D8], bl * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465713(C) | :0046571B BFD8045100 mov edi, 005104D8 <-- Wasted code space :00465720 83C9FF or ecx, FFFFFFFF :00465723 33C0 xor eax, eax <-- Wasted code space :00465725 42 inc edx :00465726 F2 repnz :00465727 AE scasb :00465728 F7D1 not ecx :0046572A 49 dec ecx :0046572B 3BD1 cmp edx, ecx :0046572D 72DD jb 0046570C * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465708(C) | :0046572F 5F pop edi :00465730 B8D8045100 mov eax, 005104D8 <-- Load pointer to flag location :00465735 5B pop ebx <-- Restore original ebx :00465736 83C450 add esp, 00000050 :00465739 C3 ret <-- Return to caller * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:004656C3(C), :004656F4(C) | :0046573A 881DD8045100 mov byte ptr [005104D8], bl <-- Scramble flag location * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00465649(C), :00465688(C) | :00465740 B8D8045100 mov eax, 005104D8 <-- Load pointer to flag location :00465745 5B pop ebx <-- Restore original ebx :00465746 83C450 add esp, 00000050 :00465749 C3 ret <-- Return to caller Well from what I gather about the above code it's a simple CD check. The routine gets the path of the CD from the registry and tries to read the sin.exe file. If not found it stores a non zero value at 005104D8. There's some wasted code (from the compiler??) in there that seems to me to be a little confusing. If you check the code flow you'll see some registers are loaded or xor'ed for no real reason. Then the code loops up a bit but will eventualy fall through and the registers that were loaded are either reloaded with new values or restored by pulling the original value off the stack... oh well. That's the CD check, so let's check the surounding code of the call that runs the CD check routine above: -- Program Code -- :00465DD3 51 push ecx :00465DD4 A3741D5100 mov dword ptr [00511D74], eax :00465DD9 E852FFFFFF call 00465D30 :00465DDE 83C404 add esp, 00000004 :00465DE1 E89A010000 call 00465F80 :00465DE6 E835F8FFFF call 00465620 <-- Call the CD check outlined above :00465DEB 8B3D801D5100 mov edi, dword ptr [00511D80] <-- Load a secondary flag, CD drive parm? :00465DF1 89442434 mov dword ptr [esp+34], eax <-- eax is always returned with 005104D8 :00465DF5 85C0 test eax, eax <-- Test for zero :00465DF7 747B je 00465E74 <-- Always fails!!, but where we want to go :00465DF9 83FF7D cmp edi, 0000007D <-- Value from the CD check :00465DFC 7D76 jge 00465E74 <-- We want to get to 465E74 to continue :00465DFE 33DB xor ebx, ebx :00465E00 85FF test edi, edi :00465E02 7E46 jle 00465E4A :00465E04 BDA01D5100 mov ebp, 00511DA0 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465E44(C) | :00465E09 8B4D00 mov ecx, dword ptr [ebp+00] * Possible StringData Ref from Data Obj ->"cddir" | :00465E0C BEF46E4800 mov esi, 00486EF4 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465E2F(C) | :00465E11 8A01 mov al, byte ptr [ecx] :00465E13 8AD0 mov dl, al :00465E15 3A06 cmp al, byte ptr [esi] :00465E17 751C jne 00465E35 :00465E19 84D2 test dl, dl :00465E1B 7414 je 00465E31 :00465E1D 8A4101 mov al, byte ptr [ecx+01] :00465E20 8AD0 mov dl, al :00465E22 3A4601 cmp al, byte ptr [esi+01] :00465E25 750E jne 00465E35 :00465E27 83C102 add ecx, 00000002 :00465E2A 83C602 add esi, 00000002 :00465E2D 84D2 test dl, dl :00465E2F 75E0 jne 00465E11 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465E1B(C) | :00465E31 33C9 xor ecx, ecx :00465E33 EB05 jmp 00465E3A * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00465E17(C), :00465E25(C) | :00465E35 1BC9 sbb ecx, ecx :00465E37 83D9FF sbb ecx, FFFFFFFF * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465E33(U) | :00465E3A 85C9 test ecx, ecx :00465E3C 7408 je 00465E46 :00465E3E 43 inc ebx :00465E3F 83C504 add ebp, 00000004 :00465E42 3BDF cmp ebx, edi :00465E44 7CC3 jl 00465E09 * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465E3C(C) | :00465E46 8B442434 mov eax, dword ptr [esp+34] * Referenced by a (U)nconditional or (C)onditional Jump at Address: |:00465E02(C) | :00465E4A 3BDF cmp ebx, edi :00465E4C 7526 jne 00465E74 * Possible StringData Ref from Data Obj ->"+set" | :00465E4E C704BDA01D5100E02A4800 mov dword ptr [4*edi+00511DA0], 00482AE0 :00465E59 47 inc edi * Possible StringData Ref from Data Obj ->"cddir" | :00465E5A C704BDA01D5100F46E4800 mov dword ptr [4*edi+00511DA0], 00486EF4 :00465E65 47 inc edi :00465E66 8904BDA01D5100 mov dword ptr [4*edi+00511DA0], eax :00465E6D 47 inc edi :00465E6E 893D801D5100 mov dword ptr [00511D80], edi * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:00465DF7(C), :00465DFC(C), :00465E4C(C) | :00465E74 68A01D5100 push 00511DA0 <-- Getting here continues the game!! :00465E79 57 push edi :00465E7A E8C1F2FBFF call 00425140 :00465E7F 6A00 push 00000000 * Possible StringData Ref from Data Obj ->"0" | :00465E81 68CCF24700 push 0047F2CC * Possible StringData Ref from Data Obj ->"usegh" | :00465E86 6850DD4800 push 0048DD50 :00465E8B E84078FDFF call 0043D6D0 :00465E90 A35C055100 mov dword ptr [0051055C], eax :00465E95 83C414 add esp, 00000014 :00465E98 D94014 fld dword ptr [eax+14] :00465E9B D81DA4C24700 fcomp dword ptr [0047C2A4] :00465EA1 DFE0 fstsw ax :00465EA3 F6C440 test ah, 40 :00465EA6 750B jne 00465EB3 -- Continuing Program Code -- Well we don't want to run the CD check and as long as eax is always returned with a value of 005104D8 we'll overwrite the call with mov eax, 005104D8. Then change the conditonal jump to a non conditional jump to continue with the game. Seems easy enough, the actual steps to crack this one are: 1. Do a full game install 2. Download the Sin v1.04 patch / CTF upgrade and install it 3. Download the two Sin v1.05 upgrades and install them 4. Make the following edits: For v1.04, edit sin.exe ============================================= Search for: E8 35 F8 FF FF at offset 414,006 Change to : B8 C8 04 51 00 Search for: 74 7B at offset 414,023 Change to : EB -- For v1.05, edit sin.exe ============================================= Search for: E8 35 F8 FF FF at offset 414,182 Change to : B8 D8 04 51 00 Search for: 74 7B at offset 414,199 Change to : EB -- 5. Enjoy the game. Thus, another tutorial comes to an end becuase we FiX'ed one more game! Static Vengeance - FiX